Spring中Bean的单例及七种创建单例的方法 |
您所在的位置:网站首页 › springboot 创建单例 › Spring中Bean的单例及七种创建单例的方法 |
1. 单例(singleton):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。eg:每个国家(spring)有一个总统(bean),国家的所有人(其他调用者)共享此总统。
2. 多例(pototype):对这个bean每次请求都会创建一个新的bean实例,类似于new
3. SpringBoot采用的是单例模式、@Component注解默认实例化的对象是单例,如果想声明成多例对象,可以使用@Scope(“pototype”)、@Respository默认单例、@Service默认单例、@Controller默认单例
4. 单例bean与单例模式: (1)单例模式:在一个JVM进程中仅有一个实例(一个运行的Java程序必定有一个自己独立的JVM),无论在程序的何处获取实例,始终都返回一个对象 eg:Java内置的Runtime,无论在程序的何处获取实例,Runtime.getRuntime == Runtime.getRuntime 结果为true(例如建立目录、数据库的连接都需要单线程操作),单例模式能避免实例的重复创建、避免多个实例引起程序逻辑错误、节约内存。 (2)Spring单例bean:Spring的单例bean是与其容器(ApplicationContext)相关的,所以在一个JVM进程中,若有多个Spring容器,即使是单例bean,也会创建多个实例(如果在实际应用中,对象的状态会改变,就使用多例)
5. Spring把bean默认设置为单例的原因: (1)提高性能,减少了新生成实例的消耗 (2)减少了JVM的垃圾回收 (3)可以快速获取到bean(单例的获取除了第一次生成之外都是从缓存中获取的)
6. 七种创建单例的方式: (1)饿汉式: public class Singleton1{ private static Singleton1 singleton1 = new Singleton1(); public static Singleton1 getSingleton1(){ return singleton1; }}singleton1作为类变量直接得到初始化,优点是在多线程环境下能够保证同步,不可能被实例化两次,但是如果singleton1在很长一段时间后才使用,意味着singleton1实例开辟的堆内存会驻留很长时间,不能延迟加载,占用内存 (2)懒汉式: public class Singleton2{ private static Singleton2 singleton1 = null; public static Singleton2 getSingleton1(){ if(singleton1 ==null){ singleton1 = new Singleton2(); } return singleton1; }}懒汉式,是在使用的时候才去创建,这样可以避免类在初始化时提前创建,但是如果在多线程的情况下,若一开始因为线程上下文切换的原因,导致两个线程都通过了if判断,这样就new出两个实例,无法保证唯一性。延迟加载,但在多线程环境下不安全。 (3)懒汉式+同步: public class Singleton3 { private static Singleton3 singleton1 = null; public synchronized Singleton3 getSingleton1() { if (singleton1 == null) { singleton1 = new Singleton3(); } return singleton1; }}这种方法通过添加同步控制,满足了懒加载和singleton1实例的唯一性,但是添加同步控制后,getSingleton1()方法是串行化的,获取时需要排队等候,效率较低。 (4)懒汉式+双重检验: ublic class Singleton4 { private static Singleton4 singleton1 = null; public static Singleton4 getSingleton1() { if (singleton1 == null) { synchronized (Singleton4.class) { if (singleton1 == null) { singleton1 = new Singleton4(); } } } return singleton1; }}若有两个线程通过了第一个check,进入第二个check是串行化的,只能有一个线程进入,保证了唯一性,也不会有同步控制,可能会引起空指针异常,但是可能会出现JVM排序的问题 (假设这个单例创建有一些其他的资源,例如Socket、Connection,这些资源在构造函数中也会被实例化,那样在创建单例的时候,就是要实例化自身还有Socket这些资源,那根据JVM的重排序和Happens-before原则,有可能会出现先实例化自身,再去实例化Socket这些资源,若在此时只实例化了自己的情况下,别的线程调用了这个单例中Socket这些资源的方法,而此时它们可能还没有被实例化,这样就会抛出空指针的异常) (5)懒汉式+双重检验+volatile Volatile关键字禁止指令重排序: public class Singleton5 { private static volatile Singleton5 singleton1 = null; public static Singleton5 getSingleton1() { if (singleton1 == null) { synchronized (Singleton5.class) { if (singleton1 == null) { singleton1 = new Singleton5(); } } } return singleton1; }}(6)Holder方式(静态内部类): public class Singleton6 { private Singleton6(){ } private static class Singleton{ private static Singleton6 singleton1 = new Singleton6(); } public static Singleton6 getInstance(){ return Singleton.singleton1; }}在Singleton6中并没有singleton1的静态成员,而是放在静态内部类Singleton中,因此Singleton6的初始化并不会实例化singleton1,只有当Singleton被主动引用的时候才会实例化。 (7)枚举法: public class Singleton7 { private Singleton7(){ } private enum Singleton{ Singleton; private final Singleton7 singleton7; Singleton(){ singleton7 = new Singleton7(); } public Singleton7 getSingleton7() { return singleton7; } }}
|
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |